﻿namespace AddressBook.Business.Event
{
	#region "Using Statements"
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Text;

	using Csla;
	using Csla.Data;
	using Csla.Validation;

	using Business.Person;
	#endregion

	[Serializable]
	public class LocationAddress : BusinessBase<LocationAddress>, IAddress
	{
		#region "Business Methods"

		#region "Private Static Member Variables"

		private static PropertyInfo<Int32> AddressIdProperty = RegisterProperty<Int32>(l => l.AddressId);
		private static PropertyInfo<String> Address1Property = RegisterProperty<String>(l => l.Address1);
		private static PropertyInfo<String> Address2Property = RegisterProperty<String>(l => l.Address2);
		private static PropertyInfo<String> CityProperty = RegisterProperty<String>(l => l.City);
		private static PropertyInfo<Int32> StateProvinceIdProperty = RegisterProperty<Int32>(l => l.StateProvinceId);
		private static PropertyInfo<String> PostalCodeProperty = RegisterProperty<String>(l => l.PostalCode);
		private static PropertyInfo<SmartDate> ModifiedDateProperty = RegisterProperty<SmartDate>(l => l.ModifiedDate);

		#endregion

		#region "Public Properties"

		public Int32 AddressId
		{
			get { return GetProperty(AddressIdProperty); }
			internal set { LoadProperty(AddressIdProperty, value); }
		}

		public String Address1
		{
			get { return GetProperty(Address1Property); }
			set { SetProperty(Address1Property, value); }
		}

		public String Address2
		{
			get { return GetProperty(Address2Property); }
			set { SetProperty(Address2Property, value); }
		}

		public String City
		{
			get { return GetProperty(CityProperty); }
			set { SetProperty(CityProperty, value); }
		}

		public Int32 StateProvinceId
		{
			get { return GetProperty(StateProvinceIdProperty); }
			set { SetProperty(StateProvinceIdProperty, value); }
		}

		public String PostalCode
		{
			get { return GetProperty(PostalCodeProperty); }
			set { SetProperty(PostalCodeProperty, value); }
		}

		public String ModifiedDate
		{
			get { return GetProperty(ModifiedDateProperty).ToString(); }
		}

		public String FullAddress
		{
			get
			{
				using (var ctx = ContextManager<AddressBook.Business.Model.AddressBookDataContext>.GetManager(AddressBook.Business.Model.Database.AddressBook))
				{
					AddressBook.Business.Model.StateProvince stateProvince = ctx.DataContext.StateProvinces.First(sp => sp.Id == this.StateProvinceId);

					if (String.IsNullOrEmpty(this.Address2))
					{
						return String.Format("{0} {1}, {2} {3}", this.Address1, this.City, stateProvince.StateProvinceCode, this.PostalCode);
					}

					return String.Format("{0} {1} {2}, {3} {4}", this.Address1, this.Address2, this.City, stateProvince.StateProvinceCode, this.PostalCode);
				}
			}
		}

		#endregion

		#endregion

		#region "Business Rules"

		protected override void AddBusinessRules()
		{
			ValidationRules.AddRule(CommonRules.StringRequired, new RuleArgs(Address1Property));
			ValidationRules.AddRule(CommonRules.StringMaxLength, new CommonRules.MaxLengthRuleArgs(Address1Property, 60));

			ValidationRules.AddRule(CommonRules.StringMaxLength, new CommonRules.MaxLengthRuleArgs(Address2Property, 60));

			ValidationRules.AddRule(CommonRules.StringRequired, new RuleArgs(CityProperty));
			ValidationRules.AddRule(CommonRules.StringMaxLength, new CommonRules.MaxLengthRuleArgs(CityProperty, 30));

			ValidationRules.AddRule(CommonRules.IntegerMinValue, new CommonRules.IntegerMinValueRuleArgs(StateProvinceIdProperty, 1));

			ValidationRules.AddRule(CommonRules.StringRequired, new RuleArgs(PostalCodeProperty));
			ValidationRules.AddRule(CommonRules.StringMaxLength, new CommonRules.MaxLengthRuleArgs(PostalCodeProperty, 15));
		}

		#endregion

		#region  "Factory Methods"

    internal static LocationAddress NewAddress()
    {
      return DataPortal.CreateChild<LocationAddress>();
    }

    internal static LocationAddress NewAddress(String address1, String address2, String city, Int32 stateProvinceId, String postalCode)
		{
			return DataPortal.CreateChild<LocationAddress>(address1, address2, city, stateProvinceId, postalCode);
		}

    internal static LocationAddress GetAddress(Int32 addressId)
		{
			return DataPortal.FetchChild<LocationAddress>(addressId);
		}

    internal static LocationAddress GetAddress(AddressBook.Business.Model.Address data)
		{
			return DataPortal.FetchChild<LocationAddress>(data);
		}

		private LocationAddress()
		{ /* require use of factory methods */ }

		#endregion

		#region "Data Access"

		protected override void Child_Create()
		{
			
		}

		private void Child_Create(String address1, String address2, String city, Int32 stateProvinceId, String postalCode)
		{
			using (BypassPropertyChecks)
			{
				this.AddressId = 0;
				this.Address1 = address1;
				this.Address2 = address2;
				this.City = city;
				this.StateProvinceId = stateProvinceId;
				this.PostalCode = postalCode;
			}
		}

		private void Child_Fetch(Int32 addressId)
		{
			using (var ctx = ContextManager<AddressBook.Business.Model.AddressBookDataContext>.GetManager(AddressBook.Business.Model.Database.AddressBook))
			{
				AddressBook.Business.Model.Address address = ctx.DataContext.Addresses.First(a => a.Id == addressId);

				using (BypassPropertyChecks)
				{
					this.AddressId = address.Id;
					this.Address1 = address.AddressLine1;
					this.Address2 = address.AddressLine2;
					this.City = address.City;
					this.StateProvinceId = address.StateProvince.Id;
					this.PostalCode = address.PostalCode;

					LoadProperty(ModifiedDateProperty, address.ModifiedDate);
				}
			}
		}

		private void Child_Fetch(AddressBook.Business.Model.Address data)
		{
			using (BypassPropertyChecks)
			{
				this.AddressId = data.Id;
				this.Address1 = data.AddressLine1;
				this.Address2 = data.AddressLine2;
				this.City = data.City;
				this.StateProvinceId = data.StateProvince.Id;
				this.PostalCode = data.PostalCode;

				LoadProperty(ModifiedDateProperty, data.ModifiedDate);
			}
		}

		private void Child_Insert(Location location)
		{
			//handled by parent.
		}

		private void Child_Update()
		{
			// update contact address data
			using (BypassPropertyChecks)
			{
				Address.UpdateAddress(this.AddressId,
															this.Address1,
															this.Address2,
															this.City,
															this.StateProvinceId,
															this.PostalCode);
			}
		}

		private void Child_DeleteSelf(Location location)
		{
			Address.RemoveAddress(this.AddressId);
		}

		#endregion
	}
}
